import 'dart:math';

import 'package:flutter/material.dart';
import 'package:vector_math/vector_math_64.dart' as vector;

class PathMatrixDemo extends StatefulWidget {
  @override
  _PathMatrixDemoState createState() => _PathMatrixDemoState();
}

class _PathMatrixDemoState extends State<PathMatrixDemo>
    with SingleTickerProviderStateMixin {
  late Animation<double> animation;
  late AnimationController controller;

  void initState() {
    super.initState();
    controller =
        AnimationController(duration: const Duration(seconds: 2), vsync: this);
    animation = Tween<double>(begin: 0, end: 1.0).animate(CurvedAnimation(
      parent: controller,
      curve: Curves.easeInOut,
    ))
      ..addListener(() {
        setState(() {});
      })
      ..addStatusListener((status) {
        if (status == AnimationStatus.completed) {
          controller.reverse();
        } else if (status == AnimationStatus.dismissed) {
          controller.forward();
        }
      });
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
        child: CustomPaint(
          painter: PathMatrixPainter(
            animationValue: animation.value,
          ),
        ),
        onTap: () {
          if (controller.status == AnimationStatus.dismissed) {
            controller.forward();
          }
          // if (controller.status == AnimationStatus.completed) {
          //   controller.reverse();
          // } else {
          //   controller.forward();
          // }
        });
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

class PathMatrixPainter extends CustomPainter {
  final double animationValue;
  PathMatrixPainter({required this.animationValue});

  @override
  void paint(Canvas canvas, Size size) {
    _drawFlippedPaper(canvas, size);
  }

  _drawFlippedCard(Canvas canvas, Size size) {
    var paint = Paint()
      ..style = PaintingStyle.fill
      ..color = Colors.blue[400]!
      ..strokeWidth = 4.0;

    var center = Offset(size.width / 2, size.height / 2);
    var path = Path();
    final rectSize = 100.0;
    path.addRect(Rect.fromCenter(
        center: Offset(center.dx, center.dy),
        width: rectSize,
        height: rectSize));
    var transform = Matrix4.identity()
      ..translate(center.dx, center.dy, 0.0)
      ..rotateX(pi * animationValue)
      ..rotateY(pi * animationValue)
      ..rotateZ(pi * animationValue)
      ..translate(-center.dx, -center.dy, 0.0);

    var transformedPath = path.transform(transform.storage);
    if (animationValue < 0.5) {
      paint.color = Colors.blue[400]!;
    } else {
      paint.color = Colors.red;
    }
    canvas.drawPath(transformedPath, paint);
  }

  _drawFlippedPaper(Canvas canvas, Size size) {
    var paint = Paint()
      ..style = PaintingStyle.fill
      ..color = Colors.green[200]!
      ..strokeWidth = 4.0;

    var center = Offset(size.width / 2, size.height / 2);
    final rectSize = 100.0;
    final topHeight = 90.0;
    final flippedSize = -10.0;

    var topPath = Path();
    topPath.moveTo(center.dx - rectSize / 2, center.dy);
    topPath.lineTo(center.dx + rectSize / 2, center.dy);
    topPath.quadraticBezierTo(
        center.dx + rectSize / 2 + flippedSize,
        center.dy - topHeight / 2,
        center.dx + rectSize / 2,
        center.dy - topHeight);
    topPath.lineTo(center.dx - rectSize / 2, center.dy - topHeight);
    topPath.quadraticBezierTo(center.dx - rectSize / 2 + flippedSize,
        center.dy - topHeight / 2, center.dx - rectSize / 2, center.dy);
    canvas.drawPath(topPath, paint);

    var bottomPath = Path();
    for (var i = 0; i < 10; ++i) {
      bottomPath.addRect(Rect.fromCenter(
          center: Offset(
              size.width / 2 + i / 1.5, center.dy + rectSize / 2 + i * 1.5),
          width: rectSize,
          height: rectSize));
      paint.color = Colors.white70.withAlpha(240 + 10 * i);
      canvas.drawPath(bottomPath, paint);
    }

    var flippedPath = Path();
    var endY = rectSize - 2 + (topHeight - 1 - rectSize) * animationValue;
    var animatedFlippedSize = 0.0;
    if (animationValue > 0.5) {
      animatedFlippedSize = flippedSize * animationValue;
    }
    var offsetX = (1 - animationValue) * 4.0;
    flippedPath.moveTo(center.dx - rectSize / 2, center.dy);
    flippedPath.lineTo(center.dx + rectSize / 2, center.dy);
    flippedPath.quadraticBezierTo(
        center.dx + rectSize / 2 + animatedFlippedSize - offsetX,
        center.dy + endY / 2,
        center.dx + rectSize / 2 - offsetX,
        center.dy + endY);

    flippedPath.lineTo(center.dx - rectSize / 2 - offsetX, center.dy + endY);
    flippedPath.quadraticBezierTo(
        center.dx - rectSize / 2 + animatedFlippedSize,
        center.dy + endY / 2,
        center.dx - rectSize / 2,
        center.dy);
    var transform = Matrix4.identity()
      ..translate(center.dx, center.dy, 0.0)
      ..rotateX(pi * animationValue)
      ..translate(-center.dx, -center.dy, 0.0);
    var transformedPath = flippedPath.transform(transform.storage);
    if (animationValue < 0.5) {
      paint.color = Colors.white;
    } else {
      paint.color = Colors.green[300]!;
    }
    canvas.drawPath(transformedPath, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}
